package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import static com.leyou.common.constants.MQConstants.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpecParamService specParamService;

    @Autowired
    private AmqpTemplate amqpTemplate;


    /**
     * 根据条件分页查询商品
     *
     * @param page       当前页码
     * @param rows       每页大小
     * @param brandId    品牌id
     * @param categoryId 分类id
     * @param id         商品的spuid
     * @param saleable   是否上架
     * @return
     */
    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows,
                                          Long brandId, Long categoryId,
                                          Long id, Boolean saleable) {
        // 根据条件分页查询
        IPage<Spu> iPage = new Page<>(page, rows);
        IPage<Spu> spuIPage =
                query().eq(null != brandId, "brand_id", brandId)
                    .eq(null != categoryId, "cid3", categoryId)
                    .eq(null!= id , "id", id)
                    .eq(null != saleable, "saleable", saleable)
                    .page(iPage);
        // 解析结果，转换对象
        // 获取当前数据总条数
        long total = spuIPage.getTotal();
        // 获取当前分页总页数
        long pages = spuIPage.getPages();
        // 获取分页记录列表
        List<Spu> records = spuIPage.getRecords();
        // 转换DTO
        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(records);

        // 给返回给前端的数据加上品牌名称以及分类
        spuDTOS.forEach(
//                new Consumer<SpuDTO>() {
//            @Override
//            public void accept(SpuDTO spuDTO) {
//                spuDTO.setBrandName(brandService.getById(spuDTO.getBrandId()).getName());
//                    String categoryNames = categoryService.listByIds(spuDTO.getCategoryIds())
//                            .stream().map(Category::getName).collect(Collectors.joining("/"));
//                    spuDTO.setCategoryName(categoryNames);
//            }
//        });

                spuDTO -> {
                    spuDTO.setBrandName(
                            brandService.getById(
                                    spuDTO.getBrandId()).getName());
                    String categoryNames = categoryService
                            .listByIds(spuDTO.getCategoryIds())
                            .stream()
                            .map(Category::getName)
                            .collect(Collectors.joining("/"));
                    spuDTO.setCategoryName(categoryNames);
                }
        );

        return new PageDTO<>(total, pages, spuDTOS);
    }


    /**
     * 商品新增
     * @param spuDTO 该商品的spu spu_detail sku
     */
    @Override
    @Transactional
    public void addSpu(SpuDTO spuDTO) {
        // 新增spu
        Spu spu = spuDTO.toEntity(Spu.class);
        // 默认是true
//        spu.setSaleable(false);
        save(spu);
        // 新增 spuDetail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        spuDetailService.save(spuDetail);
        // 新增 sku
        List<SkuDTO> skuDTOS = spuDTO.getSkus();
        List<Sku> skuList = skuDTOS.stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            // 与spu同步
            sku.setSaleable(true);
            sku.setSpuId(spu.getId());
            return sku;
        }).collect(Collectors.toList());
        skuService.saveBatch(skuList);
    }

    /**
     * 修改商品的上下架情况
     * @param gid 商品spu id
     * @param saleable 上架或下架
     */
    @Override
    @Transactional
    public void updateSaleable(Long gid, Boolean saleable) {
        // 1. 更新spu
        Spu spu = new Spu();
        spu.setId(gid);
        spu.setSaleable(saleable);
        updateById(spu);
        // 2. 更新sku
        skuService.update()
                .eq("spu_id", gid)
                // 如果一个spu_id有多个sku，那么可以排除掉已经下架的商品的修改，提升效率
                .eq("saleable", !saleable)
                .set("saleable", saleable)
                .update();

        // 3.发送MQ消息
        String routingKey = saleable ? RoutingKeyConstants.ITEM_UP_KEY : RoutingKeyConstants.ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ExchangeConstants.ITEM_EXCHANGE_NAME, routingKey, gid);
    }

    /**
     * 根据id查询商品
     * @param id 商品id
     * @return 返回商品spuDTO
     */
    @Override
    public SpuDTO querySpuById(Long id) {
        Spu spu = getById(id);
        SpuDTO spuDTO = new SpuDTO(spu);
        return spuDTO;
    }

    /**
     * 根据spuId查询spu的所有规格参数值
     * @param id 商品id
     * @param searching 是否参与搜索
     * @return 规格参数集合
     */
    @Override
    public List<SpecParamDTO> querySpecValuesByID(Long id, Boolean searching) {
        // 获取value值
        // 根据id获取spuDetail对象
        SpuDetail spuDetail = spuDetailService.getById(id);
        // 根据supDetail对象获取规格参数值
        String specification = spuDetail.getSpecification();
        // 将规格参数值 转换成 map
        JsonUtils.nativeRead(spuDetailService.getById(id).getSpecification(),
                new TypeReference<Map<Long, Object>>() {
                });

        Map<Long, Object> specValues = JsonUtils.toMap(specification, Long.class, Object.class);

        // 获取规格参数对象
        Spu spu = getById(id);
        // 调用之前写过的方法，获取商品id对应的规格参数集合
        List<SpecParamDTO> paramDTOS = specParamService.querySpecParam(spu.getCid3(), null, searching);
        // 遍历规格参数集合，添加value值
        paramDTOS.forEach(specParamDTO -> specParamDTO.setValue(specValues.get(specParamDTO.getId())));
        return paramDTOS;
    }


    /**
     * 根据商品id查询商品
     * @param id 商品id
     * @return spuDTO
     */
    @Override
    public SpuDTO queryGoodsById(Long id) {
        Spu spu = getById(id);
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetailService.getById(id));
        List<SkuDTO> skus = SkuDTO.convertEntityList(skuService.query().eq("spu_id", id).list());
        SpuDTO spuDTO = new SpuDTO(spu);
        spuDTO.setSkus(skus);
        spuDTO.setSpuDetail(spuDetailDTO);
        return spuDTO;
    }

    /**
     * 更新商品
     * @param spuDTO 更新的商品信息
     * @return 无
     */
    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        // 判断spu是否被修改

        Long spuId = spuDTO.getId();
        if (spuId != null) {
            Spu spu = spuDTO.toEntity(Spu.class);
            updateById(spu);
        }
        // 判断spuDetail是否被修改
        SpuDetail spuDetail = spuDetailService.getById(spuDTO.getId());
        if (spuDetail != null) {
            spuDetailService.updateById(spuDetail);
        }
        // 判断sku是否被修改
        List<SkuDTO> skus = spuDTO.getSkus();
        if (CollectionUtils.isEmpty(skus)) {
            return;
        }

        Map<Boolean, List<Sku>> map = skus
                .stream()
                // 转换DTO
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(
                        // 根据saleable是否为null分组，null，是新增或修改，不是null是删除
                        Collectors.groupingBy(sku -> sku.getSaleable() == null)
                );
        // 获取要新增或者修改的sku
        List<Sku> addSkuList = map.get(true);
        if (!CollectionUtils.isEmpty(addSkuList)) {
            skuService.saveOrUpdateBatch(addSkuList);
        }
        // 获取需要删除的sku
        List<Sku> deleteSkuList = map.get(false);
        // 提取sku id集合
        if (!CollectionUtils.isEmpty(deleteSkuList)) {
            List<Long> deleteIds = deleteSkuList
                    .stream()
                    .map(Sku::getId)
                    .collect(Collectors.toList());
            skuService.removeByIds(deleteIds);
        }
    }

}